﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Practices.Unity;
using Microsoft.VisualStudio.TestTools.UnitTesting;

using Rhino.Mocks;

using SharedGenomics.Workbench.Tests.TestObjects;
using SharedGenomics.Workbench.Core;

namespace SharedGenomics.Workbench.Tests.Core
{
    [TestClass]
    public class PresenterFactoryTests
    {
        private MockRepository mocks;
        private IUnityContainer container;
        private PresenterFactory presenterFactory;

        [TestInitialize]
        public void Setup()
        {
            this.mocks = new MockRepository();
            this.presenterFactory = new PresenterFactory(null);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void AddStageShouldThrowIfArgumentNull()
        {
            this.presenterFactory.AddCreationStage(null);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void GetShouldThrowIfContextNull()
        {
            this.presenterFactory.Get((IPresenterInitialisationContext)null);
        }

        [TestMethod]
        public void ShouldCallAllInitStages()
        {
            IPresenterInitialisationStage stage1 = this.mocks.StrictMock<IPresenterInitialisationStage>();
            IPresenterInitialisationStage stage2 = this.mocks.StrictMock<IPresenterInitialisationStage>();
            IPresenterInitialisationContext context = this.mocks.Stub<IPresenterInitialisationContext>();

            this.presenterFactory.AddCreationStage(stage1);
            this.presenterFactory.AddCreationStage(stage2);

            using (this.mocks.Record())
            {
                context.Current = this.mocks.Stub<IPresenter>();
                stage1.Expect(s => s.Initialise(null)).IgnoreArguments().Return(true);
                stage2.Expect(s => s.Initialise(null)).IgnoreArguments().Return(true);
                stage1.Expect(s => s.PostInitialise(null)).IgnoreArguments();
                stage2.Expect(s => s.PostInitialise(null)).IgnoreArguments();
            }

            using (this.mocks.Playback())
            {
                this.presenterFactory.Get(context);
            }
        }

        [TestMethod]
        public void ShouldShortCircuitBuildChain()
        {
            IPresenterInitialisationStage stage1 = this.mocks.DynamicMock<IPresenterInitialisationStage>();
            IPresenterInitialisationStage stage2 = this.mocks.StrictMock<IPresenterInitialisationStage>();
            IPresenterInitialisationContext context = this.mocks.Stub<IPresenterInitialisationContext>();

            this.presenterFactory.AddCreationStage(stage1);
            this.presenterFactory.AddCreationStage(stage2);

            using (this.mocks.Record())
            {
                context.Current = this.mocks.Stub<IPresenter>();
                stage1.Expect(s => s.Initialise(null)).IgnoreArguments().Return(false);
                stage1.Expect(s => s.PostInitialise(null)).IgnoreArguments();
            }

            using (this.mocks.Playback())
            {
                this.presenterFactory.Get(context);
            }
        }

        [TestMethod]
        [ExpectedException(typeof(InvalidOperationException))]
        public void GetShouldThrowIfNoStagesAdded()
        {
            IPresenterInitialisationContext context = this.mocks.Stub<IPresenterInitialisationContext>();
            this.presenterFactory.Get(context);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void GetShouldThrowIfCreatedNull()
        {
            IPresenterInitialisationStage stage1 = this.mocks.Stub<IPresenterInitialisationStage>();
            IPresenterInitialisationContext context = this.mocks.Stub<IPresenterInitialisationContext>();

            this.presenterFactory.AddCreationStage(stage1);

            using (this.mocks.Record())
            {
                stage1.Stub(s => s.Initialise(null)).IgnoreArguments().Return(true);
                stage1.Stub(s => s.PostInitialise(null)).IgnoreArguments();
            }

            using (this.mocks.Playback())
            {
                this.presenterFactory.Get(context);
            }
        }
    }
}
